﻿using System;
using System.Collections.Generic;
using Flower.Services.Data;
using NUnit.Framework;
using Flower.Workflow;
using Process = Flower.Workflow.Process;

namespace Flower.Testing.Tests
{
    [TestFixture]
    public class WorkflowTestTests
    {
        public class TestWorkflow : Process, IProcessDefinition
        {
            public bool ChecksTest;
            public bool AfterException;

            public void DefineLocalSets(ISetsBuilder bld)
            {
            }

            public void DefineProcess(IProcessBuilder process)
            {
                process
                    .Exec(_ => { })
                    .Exec(_ => { })

                    .Breakpoint("Checks test start")

                    .Name("Activity for check test")
                    .Exec(_ => { ChecksTest = true; })

                    .Breakpoint("Checks test end")

                    .Exec(_ => { })
                    .Exec(_ => { })

                    .Breakpoint("Exceptions expectation test start")

                    .Name("Throwing activity")
                    .Throw(_ => new ArgumentException("Test exception"))
                    .Exec(_ => { AfterException = true; })

                    .Breakpoint("Exceptions expectation test end")

                    .Exec(_ => { })
                    .Exec(_ => { })

                    .Breakpoint("Wait handlers test start")

                    .Name("Dequeue")
                    .Dequeue<int>(_ => "/Sets/Shared/TestSet", (_, msg) => {} )

                    .Breakpoint("Wait handlers test end");
            }
        }

        [Test]
        public void Checks()
        {
            var checksDone = new List<int>();

            new WorkflowTest<TestWorkflow>("Checks test")
                .UsingMemoryDirectory(_ => _)
                .Run(new TestWorkflow())
                .From("Checks test start").To("Checks test end")
                .CheckBefore
                (
                    "Activity for check test", 
                    (client, process) => 
                    {
                        Assert.IsFalse(process.ChecksTest);
                        checksDone.Add(1);
                    }
                )
                .CheckAfter
                (
                    "Activity for check test", 
                    (client, process) => 
                    {
                        Assert.IsTrue(process.ChecksTest);
                        checksDone.Add(1);
                    }
                )
                .Go();

            Assert.AreEqual(2, checksDone.Count);
        }

        [Test]
        public void ExceptionsExpectation()
        {
            new WorkflowTest<TestWorkflow>("Exceptions expectation test")
                .UsingMemoryDirectory(_ => _)
                .Run(new TestWorkflow())
                .From("Exceptions expectation test start").To("Exceptions expectation test end")
                .Expect<ArgumentException>("Throwing activity", ex => ex.Message == "Test exception")
                .Go();
        }

        [Test]
        public void WaitHandlers()
        {
            new WorkflowTest<TestWorkflow>("Wait handlers test")
                .UsingMemoryDirectory
                (
                    dir => 
                        dir
                            .Root("/Sets/Shared")
                                .Set("TestSet", typeof(int), 0).End()
                            .End()
                )
                .Run(new TestWorkflow())
                .From("Wait handlers test start").To("Wait handlers test end")
                .OnWaitAt
                (
                    "Dequeue", 
                    (client, process) => 
                        client.PutMessage("/Sets/Shared/TestSet", null, 1, BlobFormat.BinXml)
                )
                .Go();
        }
    }
}
